Resource 配置速查
requests 决定 Pod 能不能被调度上去、QoS 落在哪一档;limits 决定运行时会不会被限流或 OOMKill。本页把单位写法、语义区别、常用模板和踩坑点浓缩成速查表,原理详解见调度与资源管理。
单位说明
CPU
CPU 以「核」为单位,支持小数和毫核(m,millicore)两种写法,最小粒度 1m。
| 写法 | 含义 | 备注 |
|---|---|---|
1 | 1 核 | 等价于 1000m |
0.5 / 500m | 0.5 核 | 两种写法等价,推荐统一用毫核 |
100m | 0.1 核 | 小型服务 request 的常见起步值 |
CPU 是可压缩资源:用量超过 limit 时被 CFS 限流(throttle),进程变慢但不会被杀。
内存
内存以字节为单位,单位后缀分二进制和十进制两族,含义不同,不要混用:
| 后缀族 | 写法 | 进制 | 换算 |
|---|---|---|---|
| 二进制 | Ki Mi Gi Ti | 1024 | 1Mi = 1024Ki = 1,048,576 B |
| 十进制 | k M G T | 1000 | 1M = 1000k = 1,000,000 B |
| 裸数字 | 134217728 | — | 直接按字节计 |
- 建议统一用
Mi/Gi:十进制的1G比二进制的1Gi少约 7%,混用容易估错量。 - 内存后缀里还有个小写的
m表示毫字节(0.001 B),没有实际用途,写出来基本是笔误。 - 内存是不可压缩资源:用量超过 limit 直接 OOMKill(退出码 137),没有「变慢」这个中间态。
Request 与 Limit 的语义
| 维度 | requests | limits |
|---|---|---|
| 调度 | 调度器按它筛选节点:节点 allocatable 减去已分配的 requests 后还装得下,才算可行节点 | 不参与调度 |
| 运行时 | 保证能拿到的下限;节点有空闲 CPU 时按各容器 request 权重瓜分 | CPU 超限被 throttle;内存超限被 OOMKill |
| QoS | 判定 QoS 等级的输入之一 | 判定 QoS 等级的输入之一 |
| 超卖 | 节点上所有 Pod 的 requests 之和不超过 allocatable | limits 之和允许超过节点容量(超卖),代价是资源紧张时有人被限流或被杀 |
常见搭配策略
| 场景 | requests | limits | 理由 |
|---|---|---|---|
| Web 服务(nginx、Node 等) | cpu: 100m–250m,memory: 128–256Mi | 内存给 request 的 2 倍左右;CPU 不设 limit,或放宽到 request 的 3–4 倍 | 流量有峰谷,CPU 需要突发空间;内存按日常峰值留 buffer,防止抖动期 OOM |
| 批处理 / Job | cpu: 500m–1,memory: 512Mi–1Gi | 与 requests 相等(凑 Guaranteed) | 跑到一半被驱逐重来的代价最高,用 Guaranteed 换取稳定性 |
| Java 应用 | cpu: 500m–1;内存按「堆 + 非堆」估算,如堆 1g 则 memory: 1536Mi–2Gi | 内存 limit 不低于 request;CPU limit 谨慎,宁可不设 | JVM 启动期瞬时 CPU 很高,limit 卡太死会拖慢启动、引起 throttle 抖动;堆外还有元空间、直接内存、线程栈要预留 |
配置示例
容器级 requests/limits
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Namespace 级 LimitRange
给整个 namespace 设置默认值与上下限,容器没写 resources 时自动补默认 request/limit:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: demo
spec:
limits:
- type: Container
default: # 容器未声明时的默认 limits
cpu: 500m
memory: 512Mi
defaultRequest: # 容器未声明时的默认 requests
cpu: 100m
memory: 128Mi
max: # 单容器允许的上限
cpu: "2"
memory: 2Gi
min: # 单容器允许的下限
cpu: 50m
memory: 64Mi
Namespace 级 ResourceQuota
限制整个 namespace 的资源总量与对象数量,超出的 Pod 在创建时直接被拒:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: demo
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
services: "10"
persistentvolumeclaims: "5"
namespace 一旦配置了包含 requests.cpu 或 requests.memory 的 ResourceQuota,新建 Pod 的每个容器都必须显式声明对应的 request(可借助 LimitRange 的 defaultRequest 兜底),否则创建会被拒绝。
QoS 等级速查
QoS 是 Pod 级属性,由所有容器的 requests/limits 声明情况共同决定:
| QoS 等级 | 判定规则 | 节点资源紧张时 | 适用场景 |
|---|---|---|---|
| Guaranteed | 每个容器的 cpu 和 memory 都同时设置了 requests 和 limits,且二者相等 | 最后被驱逐(oom_score_adj 最小) | 关键业务、有状态服务 |
| Burstable | 至少一个容器设置了 requests 或 limits,但不满足 Guaranteed 条件 | 中间梯队,实际用量超出 requests 越多越先被驱逐 | 普通 Web 服务 |
| BestEffort | 所有容器都没有设置任何 requests 和 limits | 最先被驱逐(oom_score_adj 最大) | 一次性任务、可随时重跑的 Job |
生产核心服务建议把 requests 与 limits 设为相等:驱逐顺序排最后、OOM 优先级最低,节点压力再大也是最后一批受害者。若担心 CPU 被限流,可以只去掉 CPU 的 limit、保留足额 request,此时降级为 Burstable,但换来了 CPU 突发空间。
常见坑
CPU limit 导致 Java / Go 应用 throttle
CPU 限流由 CFS 带宽控制实现:kubelet 把 limit 换算成每个调度周期的配额 —— 周期 cpu.cfs_period_us 默认 100ms,limit: 500m 对应配额 cpu.cfs_quota_us 为 50ms。
问题在于多线程应用:Java 线程池、Go 的 goroutine 可能在一个 100ms 周期的头几毫秒就把 50ms 配额打满,然后整个容器被冻结到下个周期开始。表现为 RT 毛刺、p99 飙升,而监控里的 CPU 利用率看起来根本没用满,极具迷惑性。
排查与对策:
| 手段 | 说明 |
|---|---|
container_cpu_cfs_throttled_periods_total | 被限流的周期数,持续增长即中招 |
container_cpu_cfs_throttled_seconds_total | 累计被冻结的时长 |
| 去掉或放宽 CPU limit | 只保留 request,空闲 CPU 按 request 权重分配,弹性最好 |
| JVM 版本 | JDK 8u191+ / 11+ 能识别容器核数,更老版本会按节点核数开线程池,加剧配额消耗 |
| Go 版本 | Go 1.25 起 GOMAXPROCS 默认感知 cgroup 配额;更早版本需引入 automaxprocs 库修正 |
只配 limit 不配 request
Kubernetes 会自动把 request 补成与 limit 相等。这带来两个隐性后果:
- 调度按 limit 预留资源,节点能容纳的 Pod 数骤减,集群利用率下降;
- cpu 和 memory 都只配 limit 时,Pod 直接变成 Guaranteed —— 表面上「省事」,实际把整个服务的资源弹性焊死了。
正确姿势:request 必配,limit 按需配。
内存 limit 贴峰值配置
内存不可压缩,超限即 OOMKill,没有 throttle 那样的缓冲带。JVM、Node 这类带运行时的程序真实峰值比直觉高(堆外内存、JIT、缓存),limit 贴着观测峰值配,流量一抖就重启。
建议按「峰值 × 1.2 ~ 1.5」设置,再用 container_memory_working_set_bytes 观察长期峰值后逐步收紧。